#pragma once

#include <vector>
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/BasicBlock.h"
#include "llvm/Instruction.h"
#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Instructions.h"
#include <algorithm>
#include <sys/types.h>
#include <sys/mman.h>

#include "Instrumenter.h"
#include "Utils.h"

template<typename InnerType, int MaxRate>
class Sampler
{
public:
	template<typename T, typename InstrumenterType>
	Sampler(T t, InstrumenterType *Instr) : Enabled(true), Inner(t, Instr), Rate(1), Current(0)
	{
		ofFunc[t->getParent()->getParent()].push_back(this);
	}

	template<typename T>
	void Profile(T t)
	{
		if (Enabled && (++Current < Rate))
			return;
		Rate = Inner.Profile(t) ? 1 : min(Rate * 2, MaxRate);
		Current = 0;
	}

	static map<Function*, vector<Sampler<InnerType, MaxRate>*> > ofFunc;

	bool Enabled;
private:
	InnerType Inner;
	int Rate, Current;
};

template<typename InnerType, int MaxRate>
map<Function*, vector<Sampler<InnerType, MaxRate>*> > Sampler<InnerType, MaxRate>::ofFunc;

